const fs = require('fs');
const path = require('path');
const render = require('./render');
const template = fs.readFileSync(path.join(__dirname, './declare.template')).toString();

const { traversaDir } = require('../lib/util');
const moment = require('moment');

/**
 * 解析文件列表
 * @param {string} list 文件列表
 * @param {string} dir 绝对路径前缀
 * @param {string} type 文件类型
 */
function parse(list, prefixDir, type) {
  const dir = path.join(__dirname, prefixDir);
  const fileList = list.map((item) => {
    const relativePath = item.replace(dir, '').replace(/\.js$/, '').replace(/\\/g, '/').slice(1);
    const name = relativePath.replace(/\/(.)/g, (_, char) => {
      return char.toUpperCase();
    }) + type;
    return { relativePath, name };
  });
  const fileObj = {};
  for (const file of fileList) {
    let layerObj = fileObj;
    const layerList = file.relativePath.split('/');
    const name = layerList.pop();
    for (const layer of layerList) {
      if (!layerObj[layer]) {
        layerObj[layer] = {};
      }
      layerObj = layerObj[layer];
    }
    layerObj[name] = file.name + ';';
  }
  return { fileList, fileObj };
}

async function build({ serviceList, controllerList, socketControllerList }) {
  console.log(`[${ moment().format('yyyy-MM-DD hh:mm:ss') }] 开始编译...`);
  console.log(serviceList.concat(controllerList).concat(socketControllerList).join('\n'));
  const bengin = Date.now();
  const {
    fileList: serviceFileList,
    fileObj: serviceObj,
  } = parse(serviceList, '../service', 'Service');
  const {
    fileList: controllerFileList,
    fileObj: controllerObj,
  } = parse(controllerList, '../controller', 'Controller');
  const {
    fileList: socketControllerFileList,
    fileObj: socketControllerObj,
  } = parse(socketControllerList, '../socket/controller', 'Controller');
  const typing = render({
    serviceFileList,
    serviceObj,
    controllerFileList,
    controllerObj,
    socketControllerFileList,
    socketControllerObj,
  }, template);
  fs.writeFileSync(path.join(__dirname, '../index.d.ts'), typing);
  console.log(`编译完成，耗时(${ (Date.now() - bengin) / 1000 }ms)`);
}

/**
 * 获取文件夹下的所有js文件
 * @param {string} dir 
 */
async function getJsFileList(dir) {
  dir = path.join(__dirname, dir);
  return (await traversaDir(dir)).filter((item) => {
    return /\.js$/.test(item);
  }).sort();
}

/**
 * 文件监听
 * @param {object} watch
 * @param {string[]} watch.serviceList service列表
 * @param {string[]} watch.controllerList controller列表
 */
async function watch({
  serviceList: oldServiceList,
  controllerList: oldControllerList,
  socketControllerList: oldSocketControllerList,
}) {
  const [serviceList, controllerList, socketControllerList] = await Promise.all([
    getJsFileList('../service'),
    getJsFileList('../controller'),
    getJsFileList('../socket/controller'),
  ]);
  const list = serviceList.concat(controllerList).concat(socketControllerList);
  const oldList = oldServiceList.concat(oldControllerList).concat(oldSocketControllerList);
  if (list.length !== oldList.length) {
    build({ serviceList, controllerList, socketControllerList });
  } else {
    for (let i = 0; i < list.length; i ++) {
      if (list[i] !== oldList[i]) {
        build({ serviceList, controllerList, socketControllerList });
        break;
      }
    }
  }
  setTimeout(() => {
    watch({ serviceList, controllerList, socketControllerList });
  }, 1000);
}

const args = process.argv.slice(2);
const options = {};
for (const arg of args) {
  const [key, value] = arg.split('=');
  options[key] = value;
}

if (options.watch) {
  watch({ serviceList: [], controllerList: [] });
} else {
  Promise.all([
    getJsFileList('../service'),
    getJsFileList('../controller'),
    getJsFileList('../socket/controller'),
  ]).then(([serviceList, controllerList, socketControllerList]) => {
    build({ serviceList, controllerList, socketControllerList });
  });
}